package cn.anecansaitin.whimsy.common.extension.comboSystem.skills.rockSceptre;

import cn.anecansaitin.whimsy.common.capabilities.IManaStorage;
import cn.anecansaitin.whimsy.common.capabilities.RockScepterManaStorage;
import cn.anecansaitin.whimsy.common.entity.WeaponSwingCollision;
import cn.anecansaitin.whimsy.common.extension.comboSystem.ExtraData;
import cn.anecansaitin.whimsy.common.extension.comboSystem.IChargeableSkill;
import cn.anecansaitin.whimsy.common.item.RockSceptre;
import cn.anecansaitin.whimsy.common.register.ModEffects;
import cn.anecansaitin.whimsy.util.MathUtil;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.BlockParticleOption;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;
import software.bernie.geckolib.animatable.GeoItem;

import java.util.HashSet;
import java.util.List;
import java.util.Optional;

public class EarthQuake implements IChargeableSkill {
    @Override
    public int precastTick() {
        return 0;
    }

    @Override
    public int maxChargingTick() {
        return 4 * 20;
    }

    @Override
    public int backswingTick() {
        return 10;
    }

    @Override
    public void prePrecast(Player player, ExtraData extra) {

    }

    @Override
    public void precast(int skillTick, Player player, ExtraData extra) {

    }

    @Override
    public void preCharging(Player player, ExtraData extra) {
        if (!player.level().isClientSide) {
            extra.getData("itemStack", ItemStack.class).ifPresent((i) -> {
                RockSceptre item = (RockSceptre) i.getItem();
                item.triggerAnim(player, GeoItem.getOrAssignId(i, (ServerLevel) player.level()), "stone", "earthquake.loop");
            });
        }
    }

    @Override
    public void charging(int skillTick, Player player, ExtraData extra) {
        if (player.level() instanceof ServerLevel level && skillTick % 5 == 0) {
            Optional<ItemStack> itemStackOptional = extra.getData("itemStack", ItemStack.class);

            if (itemStackOptional.isEmpty()) {
                return;
            }

            IManaStorage manaStorage = itemStackOptional.get().getCapability(IManaStorage.MANA_STORAGE);

            if (manaStorage == null) {
                return;
            }

            if (manaStorage.getManaStored(RockScepterManaStorage.DIORITE_TYPE) < 20) {
                setChargingCanceled(extra);
                return;
            }

            manaStorage.extractMana(RockScepterManaStorage.DIORITE_TYPE, 20, false);
            HashSet<MobEffectInstance> set = new HashSet<>();

            if (skillTick >= 3 * 20) {
                if (skillTick == 3 * 20) {
                    player.level().playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.EXPERIENCE_ORB_PICKUP, player.getSoundSource(), 0.5f, 0.1F);
                }

                set.add(new MobEffectInstance(ModEffects.EARTHQUAKE.get(), 20 * 5, 2, false, false, false));
            } else if (skillTick >= 2 * 20) {
                set.add(new MobEffectInstance(ModEffects.EARTHQUAKE.get(), 20 * 5, 1, false, false, false));
            } else {
                set.add(new MobEffectInstance(ModEffects.EARTHQUAKE.get(), 20 * 5, 0, false, false, false));
            }

            WeaponSwingCollision[] collisions = WeaponSwingCollision.lowFlyingSectorRange(player, 10f, 90, 15, set);
            List<Vec3> vec3s = MathUtil.distributePointsOnTriangle(collisions[0].position(), collisions[0].getFinalPos(), collisions[collisions.length - 1].getFinalPos(), 10);

            for (Vec3 vec3 : vec3s) {
                level.sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, level.getBlockState(new BlockPos((int) vec3.x, (int) (vec3.y - 1), (int) vec3.z))), vec3.x, vec3.y, vec3.z, 10, 0.0D, 0.0D, 0.0D, 0.15F);
            }

            player.level().playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.IRON_GOLEM_STEP, player.getSoundSource(), 1, 2f);
            player.addEffect(new MobEffectInstance(ModEffects.EARTHQUAKE.get(), 5, 0, false, false, false));
        }
    }

    @Override
    public void preBackswing(Player player, ExtraData extra) {
        if (player.level() instanceof ServerLevel level) {
            extra.getData("itemStack", ItemStack.class).ifPresent((i) -> {
                RockSceptre item = (RockSceptre) i.getItem();
                item.triggerAnim(player, GeoItem.getOrAssignId(i, level), "con", "attack5.backswing");
            });

            //根据实体的地震等级来给予伤害，等级越高，伤害越高
            WeaponSwingCollision[] collisions = WeaponSwingCollision.lowFlyingSectorRange(player, 10f, 90, 15, 0, new HashSet<>(), (entity) -> {
                if (entity instanceof LivingEntity living) {
                    MobEffectInstance effect = living.getEffect(ModEffects.EARTHQUAKE.get());

                    if (effect == null) {
                        return;
                    }

                    living.hurt(living.damageSources().playerAttack(player), (effect.getAmplifier() + 1) * 18);
                    //造成伤害就移除效果
                    living.removeEffect(ModEffects.EARTHQUAKE.get());
                }
            });

            List<Vec3> vec3s = MathUtil.distributePointsOnTriangle(collisions[0].position(), collisions[0].getFinalPos(), collisions[collisions.length - 1].getFinalPos(), 30);

            for (Vec3 vec3 : vec3s) {
                level.sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, level.getBlockState(new BlockPos((int) vec3.x, (int) (vec3.y - 1), (int) vec3.z))), vec3.x, vec3.y, vec3.z, 10, 0.0D, 0.0D, 0.0D, 0.15F);
            }

            extra.putData("end", new Object());

            player.level().playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.EVOKER_CAST_SPELL, player.getSoundSource(), 2, 1.5f);
        }
    }

    @Override
    public void backswing(int skillTick, Player player, ExtraData extra) {

    }

    @Override
    public boolean canCachingKey(int skillTick, ExtraData extra) {
        return extra.getData("end", Object.class).isEmpty();
    }

    @Override
    public boolean canDeriving(int skillTick, ExtraData extra) {
        int i = skillTick - getChargedTick(extra);
        return i >= 0 && i <= backswingTick();
    }

    @Override
    public void finish(Player player, ExtraData extra) {
        IChargeableSkill.super.finish(player, extra);
        extra.removeData("end");
        extra.getData("itemStack", ItemStack.class).ifPresent((i) -> {
            RockSceptre item = (RockSceptre) i.getItem();
            item.triggerAnim(player, GeoItem.getOrAssignId(i, (ServerLevel) player.level()), "con", "idle");
            item.triggerAnim(player, GeoItem.getOrAssignId(i, (ServerLevel) player.level()), "stone", "idle");
        });
    }

    @Override
    public String getName() {
        return "earthquake";
    }
}
